package com.penglecode.nio.socket;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class EchoClient implements Runnable {

private static final Log logger = LogFactory.getLog(EchoClient.class);
	
	/**
	 * 默认ServerSocket绑定的端口号
	 */
	public static final int DEFAULT_SERVER_PORT = 9999;
	
	/**
	 * 服务器Channel绑定的端口号
	 */
	private int port;
	
	/**
	 * 服务器Channel对象，负责接受用户连接
	 */
	private SocketChannel client;
	
	/**
	 * Selector对象，负责监控所有的连接到服务器的网络事件的发生
	 */
	private Selector selector;
	
	private ConnectionHandler clientHandler;
	
	public EchoClient() {
		super();
		try {
			this.port = DEFAULT_SERVER_PORT;
			this.selector = Selector.open(); //打开Selector
			this.client = SocketChannel.open(); //打开客户端Channel
			this.client.configureBlocking(false); //设置客户端Channel为非阻塞模式
			this.client.register(selector, SelectionKey.OP_CONNECT); //注册连接服务端socket动作
			this.client.connect(new InetSocketAddress(InetAddress.getLocalHost(), this.port));
			this.clientHandler = new ClientHandler(this.selector);
		} catch (IOException e) {
			logger.error(e, e);
		}
	}

	public void run() {
		while(true){
			try {
				/**
				 * 应用Select机制轮循是否有用户感兴趣的新的网络事件发生，当没有
				 * 新的网络事件发生时，此方法会阻塞，直到有新的网络事件发生为止
				 */
				selector.select();
				/**
				 * 程序走到这里，说明有新的网络事件发生了
				 * 接着，得到活动的网络连接选择键的集合
				 */
				System.out.println(selector.keys());
				Set<SelectionKey> selectionKeys = selector.selectedKeys();
				if(selectionKeys.size() == 0){
					continue; //继续进行while循环操作
				}
				Iterator<SelectionKey> iterator = selectionKeys.iterator();
				while(iterator.hasNext()){
					SelectionKey selectionKey = iterator.next();
					iterator.remove();
					if(selectionKey.isConnectable()){ //如果此Key的通道状态为已连接
						this.clientHandler.handleConnect(selectionKey);
						continue;
					}
					if(selectionKey.isReadable()){ //如果此Key的通道状态为可读，则进行相应的读取服务端数据的操作
						this.clientHandler.handleRead(selectionKey);
						continue;
					}
					if(selectionKey.isWritable()){ //如果此Key的通道状态为可写，则进行相应的向服务端写数据的操作
						this.clientHandler.handleWrite(selectionKey);
						try {
							Thread.sleep(10000);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						continue;
					}
				}
			} catch (Exception e) {
				logger.error(e, e);
				continue; //当有异常发生时，继续进行while循环操作
			}
		}
	}
	
	public static void main(String[] args) {
		new Thread(new EchoClient()).start();
	}

}
